﻿// -----------------------------------------------------------------------
// <copyright file="ExpressionPreProcessor.cs" company="">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------

namespace TestProject.FunWithExpressions
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Linq.Expressions;

    internal class ExpressionPreProcessor : ExpressionVisitor
    {
        private readonly IEnumerable<object> _source;

        public static Expression PreProcessor(object source, Expression expression)
        {
            if (!IsValidSource(source))
            {
                return expression;
            }

            var visitor = new ExpressionPreProcessor(source);

            return visitor.Visit(expression);
        }

        private static bool IsValidSource(object source)
        {
            if (source == null)
            {
                return false;
            }

            var type = source.GetType();

            return type.IsGenericType && type.GetInterface("IEnumerable") != null;
        }

        public ExpressionPreProcessor(object source)
        {
            this._source = (IEnumerable<object>)source;
        }

        protected override Expression VisitMethodCall(MethodCallExpression node)
        {
            if (node.Method.DeclaringType == typeof(Enumerable) && node.Arguments.Count == 2)
            {

                switch (node.Method.Name)
                {
                    case "Count":
                    case "Min":
                    case "Max":
                    case "Sum":
                    case "Average":
                        var lambda = node.Arguments[1] as LambdaExpression;
                        var lambaDelegate = lambda.Compile();
                        var value = node.Method.Invoke(null, new object[] { this._source, lambaDelegate });

                        return Expression.Constant(value);
                }
            }

            return base.VisitMethodCall(node);
        }
    }

}
